﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using Wisdom.Core;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;


namespace Wisdom.IoC.Unity
{
    /// <summary>
    /// 描述：利用Microsoft Unity作为IoC/DI容器的对象管理器
    /// </summary>
    public class UnityObjectContainer : ObjectContainer
    {
        #region Private Fields
        private readonly IUnityContainer container;
        #endregion

        #region Ctor
        /// <summary>
        /// 构造函数：构造一个 <c>UnityObjectContainer</c> 类实例.
        /// </summary>
        public UnityObjectContainer()
        {
            container = new UnityContainer();
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// 获得指定类型的服务对象
        /// </summary>
        /// <param name="serviceType">指定类型服务对象类型</param>
        /// <returns>
        /// 若没有服务对象类型，则返回 NULL，否则为serviceType 对象
        /// </returns>
        protected override object DoGetService(Type serviceType)
        {
            return container.Resolve(serviceType);
        }
        /// <summary>
        /// 获得指定类型的服务对象，并overrided提供的参数
        /// </summary>
        /// <param name="serviceType">获得的服务对象类型.</param>
        /// <param name="overridedArguments">
        /// 当获得服务时参数将被overrided
        /// </param>
        /// <returns>服务对象实例.</returns>
        protected override object DoGetService(Type serviceType, object overridedArguments)
        {
            var overrides = new List<ParameterOverride>();
            Type argumentsType = overridedArguments.GetType();
            argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .ToList()
                .ForEach(property =>
                {
                    var propertyValue = property.GetValue(overridedArguments, null);
                    var propertyName = property.Name;
                    overrides.Add(new ParameterOverride(propertyName, propertyValue));
                });
            return container.Resolve(serviceType, overrides.ToArray());
        }
        /// <summary>
        /// 拆分指定类型对象
        /// </summary>
        /// <param name="serviceType">被拆分的对象类型.</param>
        /// <returns>A <see cref="System.Array"/>所有被拆分的对象.</returns>
        protected override Array DoGetServices(Type serviceType)
        {
            Guard.IsNotNull(serviceType, "serviceType");

            var instances = new List<object>();

            if (container.Registrations.Any(registration => registration.RegisteredType == serviceType && string.IsNullOrEmpty(registration.Name)))
            {
                instances.Add(container.Resolve(serviceType));
            }

            instances.AddRange(container.ResolveAll(serviceType));

            return instances.ToArray();
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// 从配置文件中初始化对象容器
        /// </summary>
        public void InitializeFromConfigFile()
        {
            InitializeFromConfigFile(UnityConfigurationSection.SectionName);
        }
        /// <summary>
        /// 从配置文件中指定名称结点初始化对象容器,从配置文件结点指定名称
        /// </summary>
        /// <param name="configSectionName">The name of the configuration section.</param>
        public override void InitializeFromConfigFile(string configSectionName)
        {
            var section = (UnityConfigurationSection)ConfigurationManager.GetSection(configSectionName);
            section.Configure(container);
        }
        /// <summary>
        /// 获得包装后的容器实例
        /// </summary>
        /// <typeparam name="T">包装容器类型.</typeparam>
        /// <returns>包装容器类型实例.</returns>
        public override T GetOriginalContainer<T>()
        {
            if (typeof(T) == typeof(UnityContainer))
                return (T)this.container;
            throw new InfrastructureException("The wrapped container type provided by the current object container should be '{0}'.", typeof(UnityContainer));
        }
        /// <summary>
        /// Register the instance as singleton.
        /// </summary>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public override IServiceRegistrar RegisterInstance(Type serviceType, object instance)
        {
            Guard.IsNotNull(serviceType, "serviceType");
            Guard.IsNotNull(instance, "instance");

            this.container.RegisterInstance(serviceType, instance);

            return this;
        }

        /// <summary>
        /// 返回一个<see cref="Boolean"/>值，标识指定类型是否被注册到服务加载器中
        /// </summary>
        /// <typeparam name="T">判断的类型.</typeparam>
        /// <returns>True 已被注册, 否则, false.</returns>
        public override bool Registered<T>()
        {
            return this.container.IsRegistered<T>();
        }
        /// <summary>
        /// 返回一个<see cref="Boolean"/>值，标识指定类型是否被注册到服务加载器中
        /// </summary>
        /// <param name="type">判断的类型.</param>
        /// <returns>True 已被注册, 否则, false.</returns>
        public override bool Registered(Type type)
        {
            return this.container.IsRegistered(type);
        }

        public override void Inject(object instance)
        {
            if (instance != null)
            {
                this.container.BuildUp(instance.GetType(), instance);
            }
        }

        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和生命周期进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public override IServiceRegistrar RegisterServiceType(Type from, Type to, LifetimeStyle lifetimeStyle)
        {
            Guard.IsNotNull(from, "from");
            Guard.IsNotNull(to, "to");

            LifetimeManager lifeTimeManager;
            switch (lifetimeStyle)
            {
                case LifetimeStyle.PerRequest:
                    lifeTimeManager = new PerRequestLifetimeManager();
                    break;
                case LifetimeStyle.Singleton:
                    lifeTimeManager = new ContainerControlledLifetimeManager();
                    break;
                default:
                    lifeTimeManager = new TransientLifetimeManager();
                    break;
            }

            if (container.Registrations.Any(registration => registration.RegisteredType == from))
            {
                container.RegisterType(from, to, to.FullName, lifeTimeManager);
            }
            else
            {
                container.RegisterType(from, to, lifeTimeManager);
            }

            return this;
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的类名称和生命周期进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <param name="name">指定的类名称</param>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public override IServiceRegistrar RegisterServiceType(Type from, Type to, string name, LifetimeStyle lifetimeStyle)
        {
            switch (lifetimeStyle)
            {
                case LifetimeStyle.Transient:
                    container.RegisterType(from, to, name, new TransientLifetimeManager());
                    break;
                case LifetimeStyle.Singleton:
                    container.RegisterType(from, to, name, new ContainerControlledLifetimeManager());
                    break;
                case LifetimeStyle.PerRequest:
                    container.RegisterType(from, to, name, new PerRequestLifetimeManager());
                    break;
            }
            return this;
        }
        #endregion

        protected override void DisposeCore()
        {
            container.Dispose();
        }
    }
}
